package imageswipe 
{
	import fl.transitions.easing.None;
	import fl.transitions.Tween;
	import fl.transitions.TweenEvent;
	import flash.display.Loader;
	import flash.display.LoaderInfo;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.net.URLRequest;
	import imageswipe.events.SelectIndexEvent;
	import imageswipe.events.SwipeEvent;
	import imageswipe.vo.ImageSwipeVO;
	
	/**
	 * ...
	 * @author ...
	 */
	[Event(name = "indexChanged", type = "imageswipe.events.SelectIndexEvent")]
	
	public class ImageSwipe extends Sprite 
	{
		public static const SWIPE_LEFT					: String = "swipeLeft";
		public static const SWIPE_RIGHT					: String = "swipeRight";
		public static const IMAGE_WIDTH					: Number = 638;
		public static const IMAGE_HEIGHT				: Number = 388;
		
		private var _background							: Sprite;
		private var _swipeArea							: Sprite;
		private var _vImagePath							: Vector.<String>;
		private var _vImageLoader						: Vector.<ImageObject>;
		private var _imageCurrent						: ImageObject;
		private var _imageNext							: ImageObject;
		private var _numberOfLoadedPrioritisedImages	: uint = 0;
		private var _numberOfPrioritisedImages			: uint = 3;
		private var _mouseDownPoint						: Point = new Point;
		private var _mouseUpPoint						: Point = new Point;
		private var _currentImageIndex					: int = 0;
		private var _customNextImageIndex				: int = -1;
		private var _twSwipeCurrent						: Tween;
		private var _swipeDirection						: String;
		private var _animationInProgress				: Boolean;
		private var _dataProvider						: ImageSwipeVO;
		
		public function ImageSwipe() 
		{
			_vImagePath = new Vector.<String>();
			_vImageLoader = new Vector.<ImageObject>();
			
			_background = new Sprite;
			_background.graphics.beginFill(0x408080);
			_background.graphics.drawRect(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);
			_background.graphics.endFill();
			
			_swipeArea = new Sprite;
			_swipeArea.graphics.beginFill(0xFFFFFF, 0);
			_swipeArea.graphics.drawRect(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);
			_swipeArea.graphics.endFill();
			_swipeArea.addEventListener(MouseEvent.MOUSE_DOWN, _onBackgroundMouseDown);
			
			addChild(_background);
			
			_draw();
		}
		
		private function _draw():void 
		{
			if (!_dataProvider || !_dataProvider is ImageSwipeVO) return;
			_vImagePath = _dataProvider.imageVO.vImagePath;
			
			_loadPrioritisedImages();
		}
		
		private function _loadPrioritisedImages():void 
		{
			var __i:int;
			if (_vImageLoader.length <= _numberOfPrioritisedImages)
			{
				for (__i = 0; __i < _numberOfPrioritisedImages; __i++)
				{
					_vImageLoader.push(new ImageObject);
					_vImageLoader[__i].ImageHolder = new Loader();
					_vImageLoader[__i].ImageHolder.contentLoaderInfo.addEventListener(Event.COMPLETE, _onPrioritisedImagedLoaded);
					_vImageLoader[__i].ImageHolder.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, _onImagedIOError);
					_vImageLoader[__i].ImageHolder.load(new URLRequest(_vImagePath[__i]));
				}
			}
		}
		
		private function _onPrioritisedImagedLoaded(e:Event):void 
		{
			_numberOfLoadedPrioritisedImages++;
			
			var __loader:LoaderInfo = LoaderInfo(e.currentTarget);
			__loader.content.removeEventListener(Event.COMPLETE, _onRestImagedLoaded);
			
			if (_numberOfLoadedPrioritisedImages == _numberOfPrioritisedImages)
			{
				trace(this, "prioritised image loaded");
				
				_positionImages();
				_loadRest();
			}
		}
		
		private function _positionImages():void 
		{
			for	(var __i:uint = 0; __i < _vImageLoader.length; __i++)
			{
				_vImageLoader[__i].ImageHolder.x = IMAGE_WIDTH * __i;
				_background.addChild(_vImageLoader[__i].ImageHolder);
			}
			//_background.width = _vImagePath.length * IMAGE_WIDTH;
			addChild(_swipeArea);
		}
		
		private function _onBackgroundMouseDown(e:MouseEvent):void 
		{
			//trace(this, "animation In Progress:::", _animationInProgress);
			if (_animationInProgress) return;
			_swipeArea.removeEventListener(MouseEvent.MOUSE_DOWN, _onBackgroundMouseDown);
			_mouseDownPoint = new Point(mouseX, mouseY);
			_swipeArea.addEventListener(MouseEvent.MOUSE_UP, _onBackgroundMouseUp);
		}
		
		private function _onBackgroundMouseUp(e:MouseEvent):void 
		{
			_swipeArea.removeEventListener(MouseEvent.MOUSE_UP, _onBackgroundMouseUp);
			_mouseUpPoint = new Point(mouseX, mouseY);
			
			if (_mouseDownPoint.x < _mouseUpPoint.x)
			{
				_swipeDirection = SWIPE_RIGHT;
				_swipeAction();
				
			}
			else if (_mouseDownPoint.x > _mouseUpPoint.x)
			{
				_swipeDirection = SWIPE_LEFT;
				_swipeAction();
			}
			else 
			{
				//no mouse movement
				_swipeArea.addEventListener(MouseEvent.MOUSE_UP, _onBackgroundMouseUp);
			}
		}
		
		private function _swipeAction():void 
		{
			var __tempCurrentIndex:int = _currentImageIndex;
			switch (_swipeDirection) 
			{
				case SWIPE_LEFT:
					_imageCurrent = _vImageLoader[_currentImageIndex];
					
					if (_customNextImageIndex >= 0) 
					{
						trace(this, "custom mode from::", _currentImageIndex, "to::", _customNextImageIndex);
						_imageNext = _vImageLoader[_customNextImageIndex];
						_currentImageIndex = _customNextImageIndex;
					}
					else
					{
						__tempCurrentIndex = _currentImageIndex;
						if (_currentImageIndex < _vImageLoader.length - 1)
						{
							trace(this, "_currentImageIndex::", _currentImageIndex, _vImageLoader.length);
							trace(this, "error ::::", _vImageLoader[_currentImageIndex + 1]);
							trace(this, _vImageLoader[_currentImageIndex + 1].ImageHolder);
							trace(this, _vImageLoader[_currentImageIndex + 1].ImageHolder.content);
							if (!_vImageLoader[_currentImageIndex + 1].ImageHolder.content) _swipeAction();//image not loaded yet
							
							_imageNext = _vImageLoader[_currentImageIndex + 1];
							_currentImageIndex++;
						}
						else 
						{
							_imageNext = _vImageLoader[0];
							_currentImageIndex = 0;
						}
						trace(this, "normal mode from::", __tempCurrentIndex, "to::", _currentImageIndex);
					}
					
					_background.x 				= 0;
					_imageCurrent.ImageHolder.x = 0;
					_imageNext.ImageHolder.x 	= IMAGE_WIDTH;
					
					while (_background.numChildren) _background.removeChildAt(0);
					
					_background.addChild(_imageCurrent.ImageHolder);
					_background.addChild(_imageNext.ImageHolder);
					
					//_twSwipeCurrent = new Tween(_background, "x", None.easeNone, 0, -IMAGE_WIDTH, 1, true);
					//_twSwipeCurrent.addEventListener(TweenEvent.MOTION_FINISH, _onTweenMotionFinish);
					
					_startTween(_swipeDirection);
					dispatchEvent(new SelectIndexEvent(SelectIndexEvent.INDEX_CHANGED, _currentImageIndex));
					dispatchEvent(new SwipeEvent(SwipeEvent.ANIMATION_IN_PROGRESS, true));
				break;
				case SWIPE_RIGHT:
					_imageCurrent = _vImageLoader[_currentImageIndex];
					if (_customNextImageIndex >= 0) 
					{
						trace(this, "custom mode from::", _currentImageIndex, "to::", _customNextImageIndex);
						_imageNext = _vImageLoader[_customNextImageIndex];
						_currentImageIndex = _customNextImageIndex;
					}
					else
					{
						__tempCurrentIndex = _currentImageIndex;
						if (_currentImageIndex > 0)
						{
							_imageNext = _vImageLoader[_currentImageIndex - 1];
							_currentImageIndex--;
							trace(this, "normal mode from 3::", __tempCurrentIndex, "to::", _currentImageIndex);
						}
						else 
						{
							if (!_vImageLoader[_vImagePath.length - 1].ImageHolder.content) _swipeAction();//image not loaded yet
							
							_imageNext = _vImageLoader[_vImagePath.length - 1];
							_currentImageIndex = _vImagePath.length - 1;
							trace(this, "normal mode from 4::", __tempCurrentIndex, "to::", _currentImageIndex);
						}
					}
					
					_background.x 				= -IMAGE_WIDTH;
					_imageCurrent.ImageHolder.x = IMAGE_WIDTH;
					_imageNext.ImageHolder.x 	= 0;
					
					while (_background.numChildren) _background.removeChildAt(0);
					
					_background.addChild(_imageCurrent.ImageHolder);
					_background.addChild(_imageNext.ImageHolder);
					
					//_twSwipeCurrent = new Tween(_background, "x", None.easeNone, -IMAGE_WIDTH, 0, 1, true);
					//_twSwipeCurrent.addEventListener(TweenEvent.MOTION_FINISH, _onTweenMotionFinish);
					_startTween(_swipeDirection);
					dispatchEvent(new SelectIndexEvent(SelectIndexEvent.INDEX_CHANGED, _currentImageIndex));
					dispatchEvent(new SwipeEvent(SwipeEvent.ANIMATION_IN_PROGRESS, true));
				break;
				default:
				break;
			}
		}
		
		private function _startTween(direction:String):void
		{
			switch (direction) 
			{
				case SWIPE_LEFT:
					trace(this, "start tweening to left");
					_animationInProgress = true;
					_twSwipeCurrent = new Tween(_background, "x", None.easeNone, 0, -IMAGE_WIDTH, 1, true);
					_twSwipeCurrent.addEventListener(TweenEvent.MOTION_FINISH, _onTweenMotionFinish);
				break;
				case SWIPE_RIGHT:
					trace(this, "start tweening to right");
					_animationInProgress = true;
					_twSwipeCurrent = new Tween(_background, "x", None.easeNone, -IMAGE_WIDTH, 0, 1, true);
					_twSwipeCurrent.addEventListener(TweenEvent.MOTION_FINISH, _onTweenMotionFinish);
				break;
				default:
					
				break;
			}
		}
		
		public function setImageIndex(index:uint):void
		{
			trace(this, _animationInProgress, "::::::set image to ::::", index, _currentImageIndex, _vImageLoader.length);
			if (_animationInProgress) return;
			_animationInProgress = true;
			if (index >= _vImagePath.length)
			{
				trace(this, "index out of bound");
				return;
			}
			else if (index > _currentImageIndex)
			{
				_swipeDirection = SWIPE_LEFT;
				_customNextImageIndex = index;
				_swipeAction();
				_startTween(_swipeDirection);
			}
			else if (index < _currentImageIndex)
			{
				_swipeDirection = SWIPE_RIGHT;
				_customNextImageIndex = index;
				_swipeAction();
				_startTween(_swipeDirection);
			}
		}
		
		private function _onTweenMotionFinish(e:TweenEvent):void 
		{
			e.currentTarget.removeEventListener(TweenEvent.MOTION_FINISH, _onTweenMotionFinish);
			_customNextImageIndex = -1;
			//trace(this, "after anitmation current index::", _currentImageIndex);
			_animationInProgress = false;
			dispatchEvent(new SwipeEvent(SwipeEvent.ANIMATION_IN_PROGRESS, false));
			_swipeArea.addEventListener(MouseEvent.MOUSE_DOWN, _onBackgroundMouseDown);
		}
		
		private function _loadRest():void 
		{
			var __i:int;
			for (__i = _numberOfPrioritisedImages; __i < _vImagePath.length; __i++)
			{
				_vImageLoader.push(new ImageObject);
				_vImageLoader[__i].ImageHolder = new Loader();
				//trace(this, _vImageLoader[__i].ImageHolder.content);
				_vImageLoader[__i].ImageHolder.contentLoaderInfo.addEventListener(Event.COMPLETE, _onRestImagedLoaded);
				_vImageLoader[__i].ImageHolder.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, _onImagedIOError);
				_vImageLoader[__i].ImageHolder.load(new URLRequest(_vImagePath[__i]));
			}
			trace(this, "Load rest::::", _vImageLoader.length);
		}
		
		private function _onRestImagedLoaded(e:Event):void 
		{
			var __loader:LoaderInfo = LoaderInfo(e.currentTarget);
			__loader.content.removeEventListener(Event.COMPLETE, _onRestImagedLoaded);
			trace(this, "************* _onRestImagedLoaded *****************");
		}
		
		private function _onImagedIOError(e:IOErrorEvent):void 
		{
			trace(this, "image error");
		}
		
		public function set dataProvider(value:ImageSwipeVO):void 
		{
			if (!value || !value is ImageSwipeVO) return;
			_dataProvider = value;
			_draw();
		}
		
	}

}